package com.planw.beetl.utils;


import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * @author blin
 */
public final class JavaUtils {

  private JavaUtils() {

    throw new UnsupportedOperationException();
  }

  /**
   * 根据名称查询索引的class
   */
  @NotNull
  public static PsiClass[] findClazzs(@NotNull Project project, @NotNull String name) {

    return PsiShortNamesCache.getInstance(project)
        .getClassesByName(name, GlobalSearchScope.allScope(project));
  }

  @NotNull
  public static PsiField[] findSettablePsiFields(final @NotNull PsiClass clazz) {

    final PsiField[] fields = clazz.getAllFields();
    final List<PsiField> settableFields = new ArrayList<>(fields.length);

    for (final PsiField f : fields) {
      final PsiModifierList modifiers = f.getModifierList();

      if (modifiers != null && (modifiers.hasModifierProperty(PsiModifier.STATIC)
          || modifiers.hasModifierProperty(PsiModifier.FINAL))) {
        continue;
      }

      settableFields.add(f);
    }

    return settableFields.toArray(new PsiField[0]);
  }

  public static boolean isElementWithinInterface(@Nullable PsiElement element) {

    if (element instanceof PsiClass && ((PsiClass) element).isInterface()) {
      return true;
    }
    PsiClass type = PsiTreeUtil.getParentOfType(element, PsiClass.class);
    return Optional.ofNullable(type).isPresent() && type.isInterface();
  }

  public static Optional<PsiClass> findClazz(@NotNull Project project, @NotNull String clazzName) {

    return Optional.ofNullable(JavaPsiFacade.getInstance(project)
        .findClass(clazzName, GlobalSearchScope.allScope(project)));
  }

  @NotNull
  public static Optional<PsiMethod> findMethod(@NotNull Project project, @Nullable String clazzName,
      @Nullable String methodName) {

    if (StringUtil.isEmptyOrSpaces(clazzName) || StringUtil.isEmptyOrSpaces(methodName)) {
      return Optional.empty();
    }

    Optional<PsiClass> clazz = findClazz(project, clazzName);
    if (clazz.isPresent()) {
      PsiMethod[] methods = clazz.get().findMethodsByName(methodName, true);
      return ArrayUtil.isEmpty(methods) ? Optional.empty() : Optional.of(methods[0]);
    }
    return Optional.empty();
  }

  public static List<PsiMethod> loadMapperPsiMethod(List<PsiClass> classMapperList, String method) {

    List<PsiMethod> nameMethodsList = new ArrayList<>();
    for (PsiClass psiClass : classMapperList) {
      PsiMethod[] ms = psiClass.getMethods();
      for (PsiMethod m : ms) {
        if (m.getName().equals(method)) {
          nameMethodsList.add(m);
        }

      }

    }
    return nameMethodsList;
  }

}
